﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

// 自定义命名空间
using StudentInfoSystem.Tests;
using StudentInfoSystem.Core.Models;
using StudentInfoSystem.Core.Models.Enums;

namespace StudentInfoSystem.Core.Tests;

[TestClass]
public sealed class StudentTests
{
    // 测试 1：属性自动 Trim 功能
    [TestMethod]
    public void Properties_ShouldAutoTrimInput()
    {
        // Arrange
        var student = new Student
        {
            Id = " 20230001 ",
            Name = " 张三 ",
            Gender = Gender.Male,
            College = "  计算机学院  "
        };

        // Assert
        Assert.AreEqual("20230001", student.Id);
        Assert.AreEqual("张三", student.Name);
        Assert.AreEqual("计算机学院", student.College);
    }

    // 测试 2：学号格式验证
    [TestMethod]
    [DataRow("20230001", true)]   // 合法
    [DataRow("123", false)]        // 过短
    [DataRow("2023ABCD", false)]   // 含字母
    [DataRow("", false)]           // 空值
    public void Id_Validation_ShouldMeetRequirements(string input, bool isValid)
    {
        // Arrange
        var student = new Student { Id = input };

        ValidationExtensions.Validate(student, out var results);

        // Act
        var actual = Validator.TryValidateProperty(input,
            new ValidationContext(student) { MemberName = "Id" },
            results);

        // Assert
        Assert.AreEqual(isValid, actual);
    }

    // 测试 3：姓名长度验证
    [TestMethod]
    [DataRow("张", false)]     // 1字符（过短）
    [DataRow("张三", true)]    // 2字符
    [DataRow("欧阳清风", true)] // 4字符
    [DataRow("慕容云海儿", false)] // 5字符（过长）
    public void Name_LengthValidation(string input, bool isValid)
    {
        // Arrange
        var student = new Student { Name = input };
        var results = new List<ValidationResult>();

        // Act
        var actual = Validator.TryValidateProperty(input,
            new ValidationContext(student) { MemberName = "Name" },
            results);

        // Assert
        Assert.AreEqual(isValid, actual);
    }

    // 测试 4：性别必填验证 (修复版本)
    [TestMethod]
    public void Gender_IsRequired_ShouldFailWhenUnset()
    {
        // Arrange
        var student = new Student()
        {
            // 设置其他必填字段，只留性别未设置
            Id = "20230001",
            Name = "测试姓名"
        }; // 未设置性别

        // Act
        var isValid = ValidationExtensions.Validate(student, out var results);
        var errors = results.ToList(); // 转换为 List 以便使用 LINQ

        Console.WriteLine($"性别：{student.Gender}");

        // Assert
        Assert.IsFalse(isValid);
        Assert.IsTrue(errors.Any(r =>
            r.ErrorMessage != null &&
            r.ErrorMessage.Contains("必须选择性别")));
    }

    // 测试 5：完整对象验证（成功场景）
    [TestMethod]
    public void Validate_ShouldPassWithValidData()
    {
        // Arrange
        var student = new Student
        {
            Id = "20230001",
            Name = "张三",
            Gender = Gender.Male
        };

        // Act
        var isValid = ValidationExtensions.Validate(student, out var results);
        var errors = results.ToList(); // 转换为 List 以便使用 LINQ

        // Assert
        Assert.IsTrue(isValid);
        Assert.AreEqual(0, results.Count);
    }

    // 测试 6：完整对象验证（多错误场景）(修复版本)
    [TestMethod]
    public void Validate_ShouldCaptureMultipleErrors()
    {
        // Arrange
        var invalidStudent = new Student
        {
            Id = "ABC",     // 无效学号
            Name = "X",     // 过短姓名
                            // 未设置性别
        };

        // Act
        var isValid = ValidationExtensions.Validate(invalidStudent, out var results);
        var errors = results.ToList(); // 转换为 List 以便使用 LINQ

        // Assert
        Assert.IsFalse(isValid);
        ValidationExtensions.PrintValidationErrors(errors);


        // 使用 LINQ 的 Any() 替代 Exists()
        Assert.IsTrue(errors.Any(r =>
            r.ErrorMessage != null &&
            r.ErrorMessage.Contains("学号必须是8位数字")));

        Assert.IsTrue(errors.Any(r =>
            r.ErrorMessage != null &&
            r.ErrorMessage.Contains("姓名长度应为2-4个字符")));

        Assert.IsTrue(errors.Any(r =>
            r.ErrorMessage != null &&
            r.ErrorMessage.Contains("必须选择性别")));

        // ID两个，其余各一个
        Assert.AreEqual(4, errors.Count); // 预期4个错误
    }

    // 测试 7：可选属性可为空值
    [TestMethod]
    public void OptionalProperties_ShouldAcceptNull()
    {
        // Arrange
        var student = new Student
        {
            Id = "20230002",
            Name = "李四",
            Gender = Gender.Female,
            Phone = null  // 明确赋空值
        };

        // Act & Assert (不应抛出异常)
        student.Phone = null;
        student.Dormitory = string.Empty;
    }
}
